﻿using FEM.Basic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PGMHelper;
using PerformIndex;

using SectionAnalysis;
using FEM.Result;
using Newtonsoft.Json;

using SecInfo = FEM.Basic.FRAM_Section.SectionInfoType;

namespace PBSD_Development
{


    /// <summary>
    /// 框架截面
    /// </summary>
    public class FrameSection : Section
    {
        /// <summary>
        /// 框架截面
        /// </summary>
        private FRAM_Section frameSection
        {
            get
            {
                return (FRAM_Section)this.secion;
            }
        }

        /// <summary>
        /// 截面信息
        /// </summary>
        private List<float> sectionInfoList
        {
            get
            {
                return this.frameSection.Info_List;
            }
        }

        /// <summary>
        /// 轴压比
        /// </summary>
        public override double AxialLoadRatio
        {
            get
            {
                //截面信息是否有误
                if (!this.isSectionCorrect()) return 0;
                //完成截面剖分
                if (this.sectionInfoList.Count == 0)
                {
                    MessageBoxExtern.Error("需完成SetCapacity！");
                    return 0;
                }
                //混凝土面积
                var Ac = this.sectionInfoList[(int)SecInfo.Ac];
                //型钢面积
                var As = this.sectionInfoList[(int)SecInfo.Asrc];
                //获得强度平均值
                var fc = ShearCapacityHelper.GetConcreteStrength(this.frameSection.Concrete_Grade, false, ShearCapacityHelper.CapacityType.Basic);
                var fy = ShearCapacityHelper.GetSteelStrength(this.frameSection.Steel_Grade, ShearCapacityHelper.CapacityType.Basic);
                //确定分母
                var divide = fc * (Ac - As) + fy * As;
                //分母是否合法
                return divide == 0 ? 0 : -this.axialLoad / divide;


            }
        }

        /// <summary>
        /// 获得等效高度
        /// </summary>
        /// <returns></returns>
        protected override double GetSectionHeight()
        {
            return this.frameSection.GetH();
        }

        /// <summary>
        /// 截面信息是否完整
        /// </summary>
        /// <returns></returns>
        protected override bool isSectionCorrect()
        {
            //截面配筋是否正确
            if (!this.frameSection.isDimensionCurrect())
                return MessageBoxExtern.Error("截面错误！"); ;
            if (!this.frameSection.is_AsCurrect())
                return MessageBoxExtern.Error("配筋错误！");
            //剪跨长度
            if (this.shearSpan <= 0)
                return MessageBoxExtern.Error("未设定剪跨长度！");

            //钢截面
            if (this.frameSection.is_SteelSection())
            {
                return this.frameSection.Steel_Grade <= 0 ?
                     MessageBoxExtern.Error("未设定型钢材料强度！") : true;
            }
            //混凝土截面
            else
            {
                //是否存在配箍信息
                if (this.frameSection.Stirrup_Sx_Ratio <= 0 || this.frameSection.Stirrup_Sy_Ratio <= 0
                    || this.frameSection.Stirrup_V_Ratio <= 0)
                    return MessageBoxExtern.Error("未设定配箍信息！");
                //材料强度
                if (this.frameSection.Concrete_Grade <= 0 || this.frameSection.Bar_Grade <= 0
                 || this.frameSection.Stirrup_Grade <= 0)
                    return MessageBoxExtern.Error("未设定材料强度！");
                //如果是型钢
                if (this.frameSection.is_SRCSection())
                {
                    return this.frameSection.Steel_Grade <= 0 ?
                     MessageBoxExtern.Error("未设定型钢材料强度！") : true;
                }
            }
            return true;
        }

        #region 承载力

        /// <summary>
        /// 设定抗剪承载力
        /// </summary>
        private bool setShearCapacity()
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return false;
            //计算剪跨比
            var lamda = (float)this.Lammda;
            //计算抗剪承载力
            var design = ShearCapacityHelper.GetCapacity(this.frameSection,
                        lamda, true, ShearCapacityHelper.CapacityType.Design, (float)this.axialLoad);
            var basic = ShearCapacityHelper.GetCapacity(this.frameSection,
                       lamda, true, ShearCapacityHelper.CapacityType.Basic, (float)this.axialLoad);
            var avg = ShearCapacityHelper.GetCapacity(this.frameSection,
                     lamda, true, ShearCapacityHelper.CapacityType.Average, (float)this.axialLoad);
            //设定承载力
            this.ShearCapacity = new CapacityObj(design, basic, avg);
            //完成承载力设定
            return true;
        }

        /// <summary>
        /// 设定抗弯承载力
        /// </summary>
        /// <returns></returns>
        private bool setMomentCapacity(int theta)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return false;
            //初始化截面分析结果
            SectionAnalysisResult saSection;
            //上传信息
            string zipJson = ZipHelper.CompressString(JsonConvert.SerializeObject(this.frameSection));
            //截面分析
            if (!this.setMomentCapacity(zipJson, theta, out saSection)) return false;
            //获得截面信息
            this.frameSection.Info_List = saSection.Info_List;
            //完成承载力设定
            return true;
        }

        /// <summary>
        /// 设定承载力
        /// </summary>
        /// <returns></returns>
        public bool SetCapacity(int theta)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return false;
            //设定抗弯承载力
            if (!this.setMomentCapacity(theta)) return false;
            //设定抗剪承载力
            if (!this.setShearCapacity()) return false;
            //计算弯剪比
            var momentCaBasic = this.GetMomentCapacity(CapacityType.AverageValue);
            var shearCaBasic = this.GetShearCapacity(CapacityType.AverageValue);
            this.msr = Math.Abs(momentCaBasic / (shearCaBasic * this.shearSpan));
            return true;
        }

        /// <summary>
        /// 计算抗剪承载力
        /// </summary>
        /// <param name="capacity"> 抗剪承载力 </param>
        /// <returns> 成功 </returns>
        public override bool GetShearCapacityObj(out CapacityObj capacity)
        {
            //初始化
            capacity = this.ShearCapacity;
            //截面信息是否存在
            if (this.frameSection.Info_List == null || this.frameSection.Info_List.Count == 0)
                this.frameSection.Info_List = new List<float> { this.frameSection.GetH() * this.frameSection.GetB() };
            //计算承载力
            if (!this.setShearCapacity()) return false;
            capacity = this.ShearCapacity;
            return true;
        }

        #endregion

        #region 变形限值

        /// <summary>
        /// 设定变形限值
        /// </summary>
        /// <param name="theta"></param>
        /// <returns></returns>
        public override bool SetLimits(bool isPosLoading, double shearForce = 0)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return false;
            //设定承载力
            if (!this.SetCapacity(isPosLoading? 0: 180)) return false;
            //计算剪跨比
            var lamda = (float)this.Lammda;
            //计算轴压比
            var alr = this.AxialLoadRatio;
            //轴压比更新
            alr = alr < 0 ? 0 : alr;
            //暂且不管钢结构
            if (this.frameSection.is_SteelSection()) return MessageBoxExtern.Error("暂不提供钢结构性能指标！");
            //如果是型钢
            else if (this.frameSection.is_SRCSection())
            {
                //判断是否为梁
                if (this.frameSection.is_Beam)
                {
                    //剪力为0
                    if (shearForce == 0) return MessageBoxExtern.Error("型钢梁需提供构件剪力！");
                    //获得性能状态
                    var level = new SRCBeamLevel((float)lamda, (float)this.msr, this.SteelRatio, this.LamdaV, this.GetVPR(shearForce));
                    //获得限值和破坏状态
                    this.limits = level.GetPerformList().ConvertAll(d => (double)d);
                    this.damageMode = (DamageMode)level.GetFailureMode();
                }
                else
                {
                    //获得性能状态
                    var level = new SRCColumnLevel((float)this.msr, (float)lamda, (float)alr, this.frameSection.Stirrup_V_Ratio, this.SteelCharact, this.GetRhoSSW(true), this.frameSection.Stirrup_Sy_Ratio, this.SteelShearCharact(true));
                    //获得性能状态
                    this.limits = level.GetPerformList().ConvertAll(d => (double)d);
                    this.damageMode = (DamageMode)level.GetFailureMode();
                }
            }
            //混凝土
            else
            {
                //判断是否为梁
                if (this.frameSection.is_Beam)
                {
                    //获得性能状态
                    var level = new RCBeamLevel((float)lamda, (float)this.msr, this.frameSection.Stirrup_V_Ratio,
                        this.frameSection.Stirrup_Sy_Ratio);
                    //获得性能状态
                    this.limits = level.GetPerformList().ConvertAll(d => (double)d);
                    this.damageMode = (DamageMode)level.GetFailureMode();
                }
                else
                {
                    //获得性能状态
                    var level = new RCColumnLevel((float)lamda, (float)this.msr, (float)alr, this.frameSection.Stirrup_V_Ratio);
                    //获得性能状态
                    this.limits = level.GetPerformList().ConvertAll(d => (double)d);
                    this.damageMode = (DamageMode)level.GetFailureMode();
                }
            }
            return true;

        }

        /// <summary>
        /// 剪压比
        /// </summary>
        /// <param name="force"></param>
        /// <returns></returns>
        private float GetVPR(double shearForce)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return 0;
            //完成截面剖分
            if (this.sectionInfoList.Count == 0)
            {
                MessageBoxExtern.Error("需完成SetCapacity！");
                return 0;
            }
            //截面信息是否有误
            if (!this.isSectionCorrect()) return 0;
            //混凝土强度
            float fc = ShearCapacityHelper.GetConcreteStrength(this.frameSection.Concrete_Grade,
                false, ShearCapacityHelper.CapacityType.Basic);
            //返回剪压比
            return (float)Math.Abs(shearForce / (fc * this.sectionInfoList[(int)SecInfo.Ac]));
        }

        /// <summary>
        /// 型钢腹板配钢率
        /// </summary>
        private float GetRhoSSW(bool is2Aixs)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return 0;
            //完成截面剖分
            if (this.sectionInfoList.Count == 0)
            {
                MessageBoxExtern.Error("需完成SetCapacity！");
                return 0;
            }
            return this.frameSection.GetWebShearArea(is2Aixs) / this.sectionInfoList[(int)SecInfo.Ac];
        }

        /// <summary>
        /// 型钢抗剪特征值
        /// </summary>
        private float SteelShearCharact(bool is2Axis)
        {
            //截面信息是否有误
            if (!this.isSectionCorrect()) return 0;
            //完成截面剖分
            if (this.sectionInfoList.Count == 0)
            {
                MessageBoxExtern.Error("需完成SetCapacity！");
                return 0;
            }
            //混凝土面积
            var Ac = this.sectionInfoList[(int)SecInfo.Ac];
            //混凝土强度
            float fc = ShearCapacityHelper.GetConcreteStrength(this.frameSection.Concrete_Grade,
                false, ShearCapacityHelper.CapacityType.Basic);
            //钢材强度
            float fa = ShearCapacityHelper.GetSteelStrength(this.frameSection.Steel_Grade,
                ShearCapacityHelper.CapacityType.Basic);
            //特征值
            return this.frameSection.GetWebShearArea(is2Axis) * fa / fc / Ac;
        }

        /// <summary>
        /// 含钢率
        /// </summary>
        private float SteelRatio
        {
            get
            {
                //完成截面剖分
                if (this.sectionInfoList.Count == 0)
                {
                    MessageBoxExtern.Error("需完成SetCapacity！");
                    return 0;
                }
                return this.sectionInfoList[(int)SecInfo.Asrc] / this.sectionInfoList[(int)SecInfo.Ac];
            }
        }

        /// <summary>
        /// 配箍特征值
        /// </summary>
        private float LamdaV
        {
            get
            {
                //截面信息是否有误
                if (!this.isSectionCorrect()) return 0;
                //混凝土强度
                float fc = ShearCapacityHelper.GetConcreteStrength(this.frameSection.Concrete_Grade,
                    false, ShearCapacityHelper.CapacityType.Basic);
                //箍筋强度
                float fyh = ShearCapacityHelper.GetSteelStrength(this.frameSection.Stirrup_Grade,
                    ShearCapacityHelper.CapacityType.Basic);
                //返回
                return this.frameSection.Stirrup_V_Ratio * fyh / fc;
            }
        }

        /// <summary>
        /// 型钢特征值
        /// </summary>
        private float SteelCharact
        {
            get
            {
                //截面信息是否有误
                if (!this.isSectionCorrect()) return 0;
                //完成截面剖分
                if (this.sectionInfoList.Count == 0)
                {
                    MessageBoxExtern.Error("需完成SetCapacity！");
                    return 0;
                }
                //混凝土面积
                var Ac = this.sectionInfoList[(int)SecInfo.Ac];
                //型钢面积
                var As = this.sectionInfoList[(int)SecInfo.Asrc];
                //混凝土强度
                float fc = ShearCapacityHelper.GetConcreteStrength(this.frameSection.Concrete_Grade,
                    false, ShearCapacityHelper.CapacityType.Basic);
                //钢材强度
                float fa = ShearCapacityHelper.GetSteelStrength(this.frameSection.Steel_Grade,
                    ShearCapacityHelper.CapacityType.Basic);
                //返回特征值
                return this.frameSection.GetSRCConfineFactor(Ac, As) * this.SteelRatio * fa / fc;
            }
        }

        #endregion

        #region 设定截面信息

        /// <summary>
        /// 设定截面尺寸
        /// </summary>
        /// <param name="dimensionList"></param>
        public void SetDimension(List<double> dimensionList)
        {
            this.frameSection.Dimension_List = dimensionList.ConvertAll(d => (float)d).ToList();
        }

        /// <summary>
        /// 设定配筋面积
        /// </summary>
        /// <param name="asList"></param>
        private void SetAs(List<int> asList)
        {
            this.frameSection.As_Info = asList;
        }

        /// <summary>
        /// 设定矩形截面
        /// </summary>
        /// <param name="width"> 截面宽度 </param>
        /// <param name="height"> 截面高度 </param>
        /// <param name="cover"> 保护层厚度 </param>
        public void SetRCRectangularSection(double width, double height, int cover)
        {
            this.frameSection.Type = 1;
            this.SetDimension(new List<double> { width, height });
            this.frameSection.Cover = cover;
        }

        /// <summary>
        /// 工形劲截面
        /// </summary>
        /// <param name="width"> 截面宽度 </param>
        /// <param name="height"> 截面高度 </param>
        /// <param name="webThick"> 腹板厚度 </param>
        /// <param name="steelHeight"> 型钢高度 </param>
        /// <param name="flangeWidth"> 翼缘宽度 </param>
        /// <param name="flangeThick"> 翼缘厚度 </param>
        /// <param name="cover"> 保护层厚度 </param>
        public void SetSRCRectangularSection13(double width, double height, 
            double webThick, double steelHeight, double flangeWidth, double  flangeThick, int cover)
        {
            this.frameSection.Type = 13;
            this.SetDimension(new List<double> { width, height, webThick, steelHeight, flangeWidth, flangeThick });
            this.frameSection.Cover = cover;
        }

        /// <summary>
        /// 对称十字劲截面
        /// </summary>
        /// <param name="width"> 截面宽度 </param>
        /// <param name="height"> 截面高度 </param>
        /// <param name="webThick"> 腹板厚度 </param>
        /// <param name="steelHeight"> 型钢高度 </param>
        /// <param name="flangeWidth"> 翼缘宽度 </param>
        /// <param name="flangeThick"> 翼缘厚度 </param>
        /// <param name="cover"> 保护层厚度 </param>
        public void SetSRCRectangularSection15(double width, double height,
            double webThick, double steelHeight, double flangeWidth, double flangeThick, int cover)
        {
            this.frameSection.Type = 15;
            this.SetDimension(new List<double> { width, height, webThick, flangeThick, steelHeight, flangeWidth });
            this.frameSection.Cover = cover;
        }

        /// <summary>
        /// 设定矩形梁配筋
        /// </summary>
        /// <param name="AsCompress"> 顶筋-正向加载受压钢筋 </param>
        /// <param name="AsTension"> 底筋-正向加载受拉钢筋 </param>
        public void SetRectBeamReinforcement(int AsCompress, int AsTension)
        {
            this.frameSection.is_Beam = true;
            this.SetAs(new List<int> { 0, AsCompress, AsTension });
        }

        /// <summary>
        /// 设定矩形柱截面
        /// </summary>
        /// <param name="Ascor"> 角筋 </param>
        /// <param name="Asx"> 除角筋外的X向（宽度方向）单侧配筋 </param>
        /// <param name="Asy"> 除角筋外的Y向（高度方向）单侧配筋 </param>
        public void SetRectColumnReinforcement(int Ascor, int Asx, int Asy)
        {
            this.frameSection.is_Beam = false;
            this.SetAs(new List<int> { Ascor, Asx, Asy });
        }

        /// <summary>
        /// 设定箍筋信息
        /// </summary>
        /// <param name="sRatio"> 面积配箍率（加载方向） </param>
        /// <param name="vRatio"> 体积配箍率 </param>
        public void SetStirrup(double sRatio, double vRatio)
        {
            this.frameSection.Stirrup_Sx_Ratio = (float)sRatio;
            this.frameSection.Stirrup_Sy_Ratio = (float)sRatio;
            this.frameSection.Stirrup_V_Ratio = (float)vRatio;
        }

        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        private FrameSection(): base()
        {
            this.secion = new FRAM_Section();
        }

        /// <summary>
        /// 构造截面
        /// </summary>
        /// <param name="shearSpan"> 剪跨长度 mm </param>
        /// <param name="axialLoad"> 轴力 N </param>
        public FrameSection(double shearSpan, double axialLoad = 0):this()
        {
            this.shearSpan = shearSpan;
            this.axialLoad = axialLoad;
        }
    }
}
